import {_decorator, Component, Node, RigidBody, EPSILON, Vec3} from 'cc';
import {Constants} from "db://assets/scripts/common/Constants";

const {ccclass, property} = _decorator;

/**
 * 角色刚体碰撞检测控制器
 */
@ccclass('CharacterRigidController')
export class CharacterRigidController extends Component {
    /**
     * 阻尼
     */
    @property
    public damping: number = 0.5;
    /**
     * 重力
     */
    @property
    public gravity: number = -10;

    /**
     * 刚体
     */
    private bodyRigid: RigidBody;
    /**
     * 是否着地
     */
    private grounded = true;
    /**
     * 线性速度
     */
    private velocity = new Vec3();
    /**
     * 当前最大速度
     */
    private currentMaxSpeed: number = 0;
    /**
     * 之前的Y角度值
     */
    private prevAngleY: number = 0;

    /**
     * 1 positive, 0 static, -1 negative
     */
    protected stateX: number = 0;
    /**
     * todo
     */
    protected stateZ: number = 0;

    /**
     * todo
     */
    private v3_0 = new Vec3();
    /**
     * todo
     */
    private v3_1 = new Vec3();

    onLoad() {
        this.bodyRigid = this.getComponent(RigidBody);
    }

    start() {
        this.prevAngleY = this.node.eulerAngles.y;
    }

    update(deltaTime: number) {
        const dt = 1000 / Constants.GAME_FRAME;
        this.updateCharacter(dt);
    }

    /**
     * 获取线性速度
     */
    getVelocity() {
        return this.velocity;
    }

    /**
     * 是否着地
     */
    getGround() {
        return this.grounded;
    }

    /**
     * 初始化角色最大速度
     *
     * @param moveSpeed 速度
     * @param ratio 速率
     */
    public initSpeed(moveSpeed: number, ratio: number = 1) {
        this.currentMaxSpeed = moveSpeed * ratio;
    }

    /**
     * 角色移动传入x和z
     *
     * @param x 横向移动
     * @param z 前后移动
     */
    public move(x: number, z: number) {
        if ((x > 0 && this.stateX < 0) || (x < 0 && this.stateX > 0) || (z > 0 && this.stateZ < 0) || (z < 0 && this.stateZ > 0)) {
            this.clearVelocity();
            // console.log("当前跟之前方向不一致则清除速度,避免惯性太大");
        }

        this.stateX = x;
        this.stateZ = z;
        // console.log("_stateX", this._stateX, "z", this._stateZ);
    }

    /**
     * 刚体停止移动
     */
    public stopMove() {
        this.stateX = 0;
        this.stateZ = 0;
        this.clearVelocity();
    }

    /**
     * 更新刚体状态
     *
     * @param dt 间隔时间
     */
    private updateCharacter(dt: number) {
        this.updateFunction(dt);

        if (!this.getGround()) return;
        if (this.stateX || this.stateZ) {
            this.v3_0.set(this.stateX, 0, this.stateZ);
            this.v3_0.normalize().negative();
            this.rigidMove(this.v3_0, 1);
        }
    }

    /**
     * 清除移动速度
     */
    public clearVelocity() {
        this.bodyRigid.clearVelocity();
    }

    /**
     * 刚体移动
     *
     * @param dir 方向
     * @param speed 速度
     */
    public rigidMove(dir: Vec3, speed: number) {
        this.bodyRigid.getLinearVelocity(this.v3_1);
        Vec3.scaleAndAdd(this.v3_1, this.v3_1, dir, speed);

        // console.log('this.v3_1' + this.v3_1);

        const ms = this.currentMaxSpeed;
        const len = this.v3_1.lengthSqr();
        let ratio = 1;
        if (len > ms) {
            if (Math.abs(this.node.eulerAngles.y - this.prevAngleY) >= 10) {
                ratio = 2;
            }
            this.prevAngleY = this.node.eulerAngles.y;
            this.v3_1.normalize();
            this.v3_1.multiplyScalar(ms / ratio);
        }
        this.bodyRigid.setLinearVelocity(this.v3_1);
        // console.log('setLinearVelocity1' + this.v3_1);
    }

    /**
     * 刷新
     *
     * @param dt 间隔
     */
    public updateFunction(dt: number) {
        // this._updateContactInfo();
        this.applyGravity();
        this.applyDamping();
        this.saveState();
    }

    /**
     * 施加阻尼
     *
     * @param dt 间隔
     */
    private applyDamping(dt = 1 / Constants.GAME_FRAME) {
        this.bodyRigid.getLinearVelocity(this.v3_1);
        // console.log('getLinearVelocity2' + this.v3_1);
        if (this.v3_1.lengthSqr() > EPSILON) {
            this.v3_1.multiplyScalar(Math.pow(1.0 - this.damping, dt));
            this.bodyRigid.setLinearVelocity(this.v3_1);
            // console.log('setLinearVelocity2' + this.v3_1);
        }
    }

    /**
     * 施加重力
     */
    private applyGravity() {
        const g = this.gravity;
        const m = this.bodyRigid.mass;
        this.v3_1.set(0, m * g, 0);
        this.bodyRigid.applyForce(this.v3_1)
    }

    /**
     * 获取线性速度
     */
    private saveState() {
        this.bodyRigid.getLinearVelocity(this.velocity);
        // console.log('getLinearVelocity3' + this.velocity  + ":" + this.grounded);
    }
}

